#ifndef __M_HELPRR_H
#define __M_HELPRR_H
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <random>
#include <sstream>
#include <iomanip> //setw()
#include <atomic>
#include <sqlite3.h>
#include <cstring>
#include <cerrno>
#include <sys/stat.h>
#include "mq_logger.hpp"

namespace chenmq
{   
   //sqlite数据库的封装操作
   class Sqlitehelper
   {
    public:
        typedef int(*SqliteCallback)(void*, int, char**, char**);
        Sqlitehelper(const std::string& dbfile)
            :_dbfile(dbfile), _handler(nullptr)
        {}

        //等级设置为串行化
        bool open(int safe_level = SQLITE_OPEN_FULLMUTEX)
        {
            int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_level,nullptr);
            if(ret != SQLITE_OK)
            {
                ELOG("创建打开数据库失败, %s\n", sqlite3_errmsg(_handler));
                return false;
            }
            return true;
        }

          //执行语句
        bool exec(const std::string& sql, SqliteCallback cb, void* arg)
        {
            int ret = sqlite3_exec(_handler, sql.c_str(), cb, arg, nullptr);
            if(ret != SQLITE_OK)
            {
                ELOG("执行sqlite语句失败:%s", sqlite3_errmsg(_handler));
                return false;
            }
            return true;
        } 

        void close()
        {
            if(_handler)
                sqlite3_close_v2(_handler);
        }
    private:
        std::string _dbfile;
        sqlite3* _handler;
   };

    //字符串分割操作
    class StrHelper
    {
    public:
        static size_t split(const std::string &str, const std::string &sep, std::vector<std::string> &result) 
        {
            size_t pos, idx = 0;
            while(idx < str.size()) 
            {
                pos = str.find(sep, idx);
                if (pos == std::string::npos) 
                {
                    result.push_back(str.substr(idx));
                    return result.size();
                }
                if (pos == idx) 
                {
                    idx = pos + sep.size();
                    continue;
                }
                result.push_back(str.substr(idx, pos - idx));
                idx = pos + sep.size();
            }
            return result.size();
        }
    };

    //UUID生成器类, 生成8个随机数字
    //思想：
    // 生成8个 0--255之间的随机数 uniform_int_distribution<int> distribution(0, 255);
    // 取出一个8字节的序号
    class UUIDHelper
    {
    public:
        static std::string uuid()
        {
            std::random_device rd; //机器随机数，直接生成效率低
            std::mt19937_64 generator(rd()); //梅森旋转算法，生成一个伪随机数
            std::uniform_int_distribution<int> distribution(0, 255); //限定区间
            std::stringstream ss;
            for(int i = 0; i < 8; i++)
            {
                ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator);
                if(i == 3 || i == 5 || i == 7)
                {
                    ss << "-";
                }
            }

            static std::atomic<size_t> seq(1); //定义一个原子类型整数，初始化为1
            size_t num = seq.fetch_add(1);
            for(int i = 7; i >= 0; i--)
            {
                ss << std::setw(2) << std::setfill('0') << std::hex << ((num >> (i * 8)) & 0xff);
                if(i == 6)
                    ss << "-";
            }

            return ss.str();
        }
    };

    //文件基础操作
    class FileHelper
    {
    public:
        FileHelper(const std::string& filename)
            :_filename(filename)
        {}

        bool exists()
        {
            //stat函数，成功返回0（检查文件是否存在且可访问），失败返回-1
            struct stat st;
            return (stat(_filename.c_str(), &st) == 0); 
        }

        size_t size()
        {
            struct stat st;
            int ret = stat(_filename.c_str(), &st);
            if(ret < 0)
            {
                return 0;
            }
            return st.st_size;
        }

        bool read(char* body, size_t offset, size_t len)
        {
            //1,打开文件
            std::ifstream ifs(_filename, std::ios::binary | std::ios::in);
            if(ifs.is_open())
            {
                ELOG("打开文件失败 %s", _filename.c_str());
                return false;
            }

            //2,跳转文件读写位置
            ifs.seekg(offset, std::ios::beg);

            //3,从offset位置开始读取文件
            ifs.read(body, len);
            if(ifs.good() == false)
            {
                ELOG("文件读取数据失败 %s", _filename.c_str());
                ifs.close();
                return false;
            }

            ifs.close();
            return true;
        }

        bool read(std::string& body)
        {
            size_t fsize = this->size(); //获取文件的大小
            body.resize(fsize);
            return read(&body[0], 0, fsize);
        }

        bool write(const char* body, size_t offset, size_t len)
        {
            //打开文件
            std::fstream fs(_filename, std::ios::binary | std::ios::in | std::ios::out);
            if(fs.is_open() == false)
            {
                ELOG("文件打开失败: %s", _filename.c_str());
                return false;
            }

            //跳转到文件指定位置
            fs.seekp(offset, std::ios::beg); //seekg用于输入流，seekp用于输出流

            //开始向文件写数据
            fs.write(body, len);
            if(fs.good() == false)
            {
                ELOG("文件写入失败 %s", _filename.c_str());
                fs.close();
                return false;
            }

            fs.close();
            return true;
        }

        bool write(const std::string& body)
        {
            return write(body.c_str(), 0, body.size());
        }

        bool rename(const std::string& nname)
        {
            return (::rename(_filename.c_str(), nname.c_str()) == 0);
        }

        static std::string parentDirectory(const std::string& filename)
        {
            //  /a/b/c/d/test.txt
            size_t pos = filename.find_last_of("/");
            if(pos == std::string::npos)
            {
                return  "./";
            }
            std::string path = filename.substr(0, pos);
            return path;
        }

        static bool createFile(const std::string& filename)
        {
            //对于输出流来说，不存在就创建文件
            std::fstream ofs(filename, std::ios::binary | std::ios::out);
            if(ofs.is_open() == false)
            {
                ELOG("文件打开失败: %s", filename.c_str());
                return false;
            }

            ofs.close();
            return true;
        }

        static bool removeFile(const std::string& filename)
        {
            return (::remove(filename.c_str()) == 0);
        }

        static bool createDirectory(const std::string& path)
        {
            //在多级目录的情况下，需要从第一个父级目录开始创建
            size_t pos = 0;
            size_t idx = 0;
            while(idx < path.size())
            {
                pos = path.find("/", idx);
                if(pos == std::string::npos)
                {
                    return (mkdir(path.c_str(), 0755) == 0);
                }

                std::string subpath = path.substr(0, pos);
                int ret = mkdir(subpath.c_str(), 0775);
                // EEXIST 是系统错误码，表示路径已存在,如果失败且错误不是“目录已存在”，则进入错误处理
                if(ret != 0 && errno != EEXIST) 
                {
                    ELOG("创建目录失败 %s, %s", subpath.c_str(), strerror(errno));
                    return false;
                }
                idx = pos + 1;
            }
            return true;
        }

        static bool removeDirectory(const std::string& path)
        {
            std::string cmd = "rm -rf" + path;
            return (system(cmd.c_str()) != -1);
        }
    private:
        std::string _filename;   
    };
} 







#endif
